package com.gitee.wsl.mathematics.geometry.d2.base

import com.gitee.wsl.mathematics.geometry.api.AnchorAble
import com.gitee.wsl.mathematics.interpolator.PercentOrRatio
import com.gitee.wsl.mathematics.interpolator.Ratio
import com.gitee.wsl.mathematics.interpolator.ext.interpolate
import com.gitee.wsl.mathematics.interpolator.ext.times
import com.gitee.wsl.mathematics.interpolator.ext.toRatio
import com.gitee.wsl.mathematics.vector.vec2.Vec2f


interface AnchorAble2d<T:Number,A: AnchorAble2d<T, A>>:AnchorAble<A>{
    val sx: T
    val sy: T

    fun withX(sx: Number): A
    fun withY(sy: Number): A

    fun withX(ratioX: Ratio): A
    fun withY(ratioY: Ratio): A

    fun interpolate(ratio: Ratio, other: A): A
}


data class Anchor(override val sx: Float,
                  override val sy: Float) : AnchorAble2d<Float, Anchor> {
    constructor(sx: Double, sy: Double) : this(sx.toFloat(), sy.toFloat())
    constructor(sx: Int, sy: Int) : this(sx.toFloat(), sy.toFloat())

    fun toVector(): Vec2f = Vec2f(sx, sy)

    val ratioX: Ratio get() = sx.toRatio()
    val ratioY: Ratio get() = sy.toRatio()

    override  fun withX(sx: Number): Anchor = Anchor(sx.toDouble(), sy)
    override  fun withY(sy: Number): Anchor = Anchor(sx, sy.toDouble())

    override  fun withX(ratioX: Ratio): Anchor = Anchor(ratioX.toDouble(), sy)
    override  fun withY(ratioY: Ratio): Anchor = Anchor(sx, ratioY.toDouble())

    companion object {
        inline operator fun invoke(sx: Ratio, sy: Ratio): Anchor = Anchor(sx.toDouble(), sy.toDouble())
        inline operator fun invoke(sx: Number, sy: Number): Anchor = Anchor(sx.toDouble(), sy.toDouble())

        val TOP_LEFT: Anchor = Anchor(0f, 0f)
        val TOP_CENTER: Anchor = Anchor(.5f, 0f)
        val TOP_RIGHT: Anchor = Anchor(1f, 0f)

        val MIDDLE_LEFT: Anchor = Anchor(0f, .5f)
        val MIDDLE_CENTER: Anchor = Anchor(.5f, .5f)
        val MIDDLE_RIGHT: Anchor = Anchor(1f, .5f)

        val BOTTOM_LEFT: Anchor = Anchor(0f, 1f)
        val BOTTOM_CENTER: Anchor = Anchor(.5f, 1f)
        val BOTTOM_RIGHT: Anchor = Anchor(1f, 1f)

        val TOP: Anchor get() = TOP_CENTER
        val LEFT: Anchor get() = MIDDLE_LEFT
        val RIGHT: Anchor get() = MIDDLE_RIGHT
        val BOTTOM: Anchor get() = BOTTOM_CENTER
        val CENTER: Anchor get() = MIDDLE_CENTER
    }

    override fun interpolate(ratio: Ratio, other: Anchor): Anchor = Anchor(
        ratio.interpolate(this.sx, other.sx),
        ratio.interpolate(this.sy, other.sy)
    )

    override fun interpolate(pet: PercentOrRatio): Anchor = Anchor(this.sx * pet,sy * pet)

    fun toNamedString(): String = when (this) {
        TOP_LEFT -> "Anchor.TOP_LEFT"
        TOP -> "Anchor.TOP"
        TOP_RIGHT -> "Anchor.TOP_RIGHT"
        LEFT -> "Anchor.LEFT"
        CENTER -> "Anchor.MIDDLE_CENTER"
        RIGHT -> "Anchor.RIGHT"
        BOTTOM_LEFT -> "Anchor.BOTTOM_LEFT"
        BOTTOM_CENTER -> "Anchor.BOTTOM_CENTER"
        BOTTOM_RIGHT -> "Anchor.BOTTOM_RIGHT"
        else -> toString()
    }
}